﻿using System.Drawing;
using System.Runtime.InteropServices;
using System.ComponentModel;


namespace System.Windows.Forms {

	public class RichTextBoxCtrl : RichTextBox {

		#region RichTextBox初始化属性

		/// <summary>
		/// richTextBox= this;
		/// </summary>
		private System.Windows.Forms.RichTextBox richTextBox1;

		public RichTextBoxCtrl() {
			AllowDrop = true;
			EnableAutoDragDrop = true;
			AcceptsTab = true;
			HideSelection = false;
			ScrollBars = RichTextBoxScrollBars.Vertical;
			InitialRichTextBoxCtrl();

		}

		#endregion

		#region RichTextBox 新建 打开 和 保存 文件对话框

		private string fileName = "未命名.rtf";
		private string absFileName = "";

		//文件名 返回 如 abc.rtf  
		public string FileName {
			get { return fileName; }
		}

		//格式 C:\windows\abc.rtf
		public string AbsFileName {
			get { return absFileName; }
		}

		/// <summary>
		/// 新空的文档
		/// </summary>
		public void NewDocument() {

			richTextBox1.Text = "";
			richTextBox1.Modified = false;

			absFileName = "";
			fileName = "";
		}

		#endregion

		#region 把RTF文件保存为纯文本

		/// <summary>
		/// 把RTF文件保存为纯文本
		/// 只保存字符 转换后文本不包括RTF中的图片信息
		/// </summary>
		/// <param name="TextFileName">"C:\Users\Admin\Desktop\CurRoleBase.txt"</param>
		public void SaveToTextFile(string TextFileName) {
			this.SaveFile(TextFileName, RichTextBoxStreamType.TextTextOleObjs);
		}

		#endregion

		#region 设置为只读模式

		[DllImport("user32.dll")]
		static extern bool HideCaret(IntPtr hWnd);


		/// <summary>
		/// HideCaret 
		/// </summary>
		/// <param name="m"></param>
		protected override void WndProc(ref Message m) {
			base.WndProc(ref m);
			if (ReadOnly)
				HideCaret(Handle);
		}

		#endregion

		#region 设置 和 获得光标所在的行号和列号

		///要在本类中初始化 richTextBox= this;
		private int EM_LINEINDEX = 0x00BB;

		private int EM_LINEFROMCHAR = 0x00C9;

		[DllImport("user32.dll", EntryPoint = "SendMessage")]
		public static extern int SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam);


		/// <summary>
		/// 获得光标所在的行号和列号
		/// </summary>
		/// <param name="editControl"></param>
		/// <returns>p.X = 行号 p.Y =列号</returns>
		public Point GetCaretPosition() {
			int charIndex = (int) SendMessage(richTextBox1.Handle, EM_LINEINDEX, -1, 0);
			int lineIndex = (int) SendMessage(richTextBox1.Handle, EM_LINEFROMCHAR, charIndex, 0);
			Point pt = new Point();
			pt.X = richTextBox1.SelectionStart - charIndex + 1; //Line
			pt.Y = lineIndex + 1; //Column
			return pt;
		}


		/// <summary>
		/// 转到行
		/// </summary>
		/// <param name="Line">行号</param>
		public void jumpLine(int Line) {
			richTextBox1.SelectionStart = SendMessage(richTextBox1.Handle, EM_LINEINDEX, Line - 1, 0);
			richTextBox1.SelectionLength = 0;
			richTextBox1.ScrollToCaret();
		}


		/// <summary>
		/// 有问题 同时设置行号和列号就出现问题了
		/// </summary>
		/// <param name="Column"></param>
		public void jumpColumn(int Column) {
			int Line = Column;

			int charIndex = (int) SendMessage(richTextBox1.Handle, EM_LINEINDEX, Line - 1, 0);
			int lineIndex = charIndex + (int) SendMessage(richTextBox1.Handle, EM_LINEFROMCHAR, charIndex, 0);

			richTextBox1.SelectionStart = lineIndex;
		}

		#endregion

		#region RichTextBox 字体样式

		//格式刷


		/// richTextBox= this;
		/// <summary>
		/// 粗体
		/// </summary>
		public void ToggleBold() {
			if (richTextBox1.SelectionFont == null)
				richTextBox1.SelectionFont = richTextBox1.Font;

			FontStyle style = richTextBox1.SelectionFont.Style;

			if (richTextBox1.SelectionFont.Bold)

				style &= ~FontStyle.Bold; //恢复正常
			else
				style |= FontStyle.Bold;

			richTextBox1.SelectionFont = new Font(richTextBox1.SelectionFont, style);
		}

		/// <summary>
		/// 斜体
		/// </summary>
		public void ToggleItalic() {
			if (richTextBox1.SelectionFont == null)
				richTextBox1.SelectionFont = richTextBox1.Font;

			FontStyle style = richTextBox1.SelectionFont.Style;

			if (richTextBox1.SelectionFont.Italic)
				style &= ~FontStyle.Italic; //恢复正常
			else
				style |= FontStyle.Italic;

			richTextBox1.SelectionFont = new Font(richTextBox1.SelectionFont, style);
		}

		/// <summary>
		/// 下划线
		/// </summary>
		public void ToggleUnderLine() {
			if (richTextBox1.SelectionFont == null)
				richTextBox1.SelectionFont = richTextBox1.Font;

			FontStyle style = richTextBox1.SelectionFont.Style;

			if (richTextBox1.SelectionFont.Underline)
				style &= ~FontStyle.Underline; //恢复正常
			else
				style |= FontStyle.Underline;

			richTextBox1.SelectionFont = new Font(richTextBox1.SelectionFont, style);
		}

		/// <summary>
		/// 删除线
		/// </summary>
		public void ToggleStrikeout() {
			if (richTextBox1.SelectionFont == null)
				richTextBox1.SelectionFont = richTextBox1.Font;

			FontStyle style = richTextBox1.SelectionFont.Style;

			if (richTextBox1.SelectionFont.Strikeout)
				style &= ~FontStyle.Strikeout; //恢复正常
			else
				style |= FontStyle.Strikeout;
			richTextBox1.SelectionFont = new Font(richTextBox1.SelectionFont, style);
		}


		/// <summary>
		/// 设置上标
		/// </summary>
		[Browsable(false)]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		public bool SelectionSupperScript {
			get { return (SelectionCharOffset == 4); }
			set {
				if (SelectionCharOffset == 0) {
					SelectionCharOffset = 4;
				} else {
					SelectionCharOffset = 0;
				}
			}
		}

		/// <summary>
		/// 设置下标
		/// </summary>
		[Browsable(false)]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		public bool SelectionSubScript {
			get { return (SelectionCharOffset == -4); }
			set {
				if (SelectionCharOffset == 0) {
					SelectionCharOffset = -4;
				} else {
					SelectionCharOffset = 0;
				}

			}
		}

		//只须设置 不需要获得是否设置的返回值
		////Tab->
		public void Indent() {
			SelectionIndent += 8;
		}

		////Tab <-
		public void OutIndent() {
			SelectionIndent -= 8;
		}

		#endregion

		#region RichTextBox Margin

		private struct Rect {

			public int Left;
			public int Top;
			public int Right;
			public int Bottom;

		}

		[DllImport("user32.dll")]
		private static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, ref Rect lParam);

		private const int EM_GETRECT = 0x00b2;
		private const int EM_SETRECT = 0x00b3;

		/// <summary>
		/// 当没设置的时候结果多出了L T R +2
		/// </summary>
		private Rect RichTextBoxMargin {
			get {
				Rect rect = new Rect();
				SendMessage(richTextBox1.Handle, EM_GETRECT, IntPtr.Zero, ref rect);
				rect.Left += 1;
				rect.Top += 1;
				rect.Right = +richTextBox1.DisplayRectangle.Width - rect.Right;
				rect.Bottom = richTextBox1.DisplayRectangle.Height - rect.Bottom;
				return rect;
			}
			set {
				Rect rect;
				rect.Left = richTextBox1.ClientRectangle.Left + value.Left;
				rect.Top = richTextBox1.ClientRectangle.Top + value.Top;
				rect.Right = richTextBox1.ClientRectangle.Right - value.Right;
				rect.Bottom = richTextBox1.ClientRectangle.Bottom - value.Bottom;

				SendMessage(richTextBox1.Handle, EM_SETRECT, IntPtr.Zero, ref rect);
			}

		}

		#endregion

		#region RichTextBox 默认快捷键

		/*
		    查找    CTRL+F
		    替换    CTRL+R
		    时间日期     F5

		    粗体    CTRL+B
		    斜体    CTRL+I
		    下划线    CTRL+U
		 */

		protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
			if (!this.ReadOnly) {
				switch (keyData) {
					//CTRL+B
					case Keys.Control | Keys.B:
						ToggleBold();
						return true;

					//CTRL+I
					case Keys.Control | Keys.I:
						ToggleItalic();
						return true;

					//CTRL+U
					case Keys.Control | Keys.U:
						ToggleUnderLine();
						return true;

					//shift +tab 左缩进
					case Keys.Shift | Keys.Tab:
						if (SelectedText != "") {
							SelectionIndent -= 8;
						}
						return true;

					//shift +tab 右缩进
					case Keys.Tab:
						if (SelectedText != "") {
							SelectionIndent += 8;

						}
						return true;

					//替换对话框
					case Keys.Control | Keys.R:
						return true;

					//插入时间日期
					case Keys.F5:
						//2013-11-13:57:09
						SelectedText = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss");
						return true;

					//粘贴纯文本
					case Keys.Control | Keys.Shift | Keys.V:
						PasteAsText();
						return true;

					case Keys.Control | Keys.G:
						return true;

				}
			}

			if (keyData == (Keys.Control | Keys.F)) {
			}
			return false;
		}

		#endregion

		#region RichTextBox 常用属性

		public void PasteAsText() {
			richTextBox1.SelectedText = Clipboard.GetText(); //粘贴纯文本
		}

		public void PasteAsBmp() {
			if (CanPasteAsBmp()) {
				richTextBox1.Paste();
			}
		}

		public void PasteAsHtml() {

		}

		public void PasteAsUnicode() {

		}

		/// <summary>
		/// 剪切板是否为空
		/// </summary>
		/// <returns></returns>
		public bool CanPaste() {
			return (Clipboard.GetDataObject() != null);
		}

		/// <summary>
		/// 剪切板是否有字符串
		/// </summary>
		/// <returns></returns>
		public bool CanPasteAsText() {
			return Clipboard.GetDataObject().GetDataPresent(DataFormats.Text);
		}

		/// <summary>
		/// 剪切板是否有位图
		/// </summary>
		/// <returns></returns>
		public bool CanPasteAsBmp() {
			return Clipboard.GetDataObject().GetDataPresent(DataFormats.Bitmap);
		}

		/// <summary>
		/// 剪切板是否HTML
		/// </summary>
		/// <returns></returns>
		public bool CanPasteAsHtml() {
			return Clipboard.GetDataObject().GetDataPresent(DataFormats.Html);
		}

		/// <summary>
		/// 是否可以全选
		/// </summary>
		/// <returns></returns>
		public bool CanSelectAll() {
			return (richTextBox1.SelectedText.Length != richTextBox1.Text.Length);
		}

		private void InitialRichTextBoxCtrl() {
			//ContextMenuStrip = contextMenuStrip1;
			LinkClicked += new System.Windows.Forms.LinkClickedEventHandler(richTextBox1_LinkClicked);
		}

		/// <summary>
		/// 自动打开超链接
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void richTextBox1_LinkClicked(object sender, LinkClickedEventArgs e) {
			DialogResult b = MessageBox.Show("你要打开此链接吗?\n" + e.LinkText, "提示", MessageBoxButtons.YesNo,
				MessageBoxIcon.Exclamation);
			if (b == DialogResult.Yes) {
				System.Diagnostics.Process.Start("iexplore.exe", e.LinkText);
			}
		}

		#endregion

		#region RichTextBox 通用对话框

		#endregion

		#region 支持表格正确粘贴

		// P/Invoke declarations
		[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
		private static extern IntPtr LoadLibrary(string path);

		private static IntPtr moduleHandle;

		protected override CreateParams CreateParams {
			get {
				if (moduleHandle == IntPtr.Zero) {
					moduleHandle = LoadLibrary("msftedit.dll");
					if ((long) moduleHandle < 0x20) {
						throw new Win32Exception(Marshal.GetLastWin32Error(), "Could not load Msftedit.dll");
					}
				}

				CreateParams createParams = base.CreateParams;
				createParams.ClassName = "RichEdit50W";
				if (this.Multiline) {
					if (((this.ScrollBars & RichTextBoxScrollBars.Horizontal) != RichTextBoxScrollBars.None) &&
					    !base.WordWrap) {
						createParams.Style |= 0x100000;
						if ((this.ScrollBars & ((RichTextBoxScrollBars) 0x10)) != RichTextBoxScrollBars.None) {
							createParams.Style |= 0x2000;
						}
					}
					if ((this.ScrollBars & RichTextBoxScrollBars.Vertical) != RichTextBoxScrollBars.None) {
						createParams.Style |= 0x200000;
						if ((this.ScrollBars & ((RichTextBoxScrollBars) 0x10)) != RichTextBoxScrollBars.None) {
							createParams.Style |= 0x2000;
						}
					}
				}
				if ((BorderStyle.FixedSingle == base.BorderStyle) && ((createParams.Style & 0x800000) != 0)) {
					createParams.Style &= -8388609;
					createParams.ExStyle |= 0x200;
				}
				return createParams;
			}
		}

		#endregion

	}

}